// HSS.Logging.LogServer.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       LogServer.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Logging
{
	#region Using Directives
	using System;
	using System.ComponentModel;
	using System.Data;
	using System.Data.SqlClient;
	using System.Diagnostics;
	using System.IO;
	using System.Security.Permissions;
	using System.Text;
	using System.Threading;
	using HSS.Data;
	using HSS.IO;
	using System.ServiceModel;
	using System.Collections.Generic;
	#endregion

	#region LogServer
	/// <summary>
	/// The LogServer is a WCF Service that is hosted by the HSS.Logging.LogService (an NTService)
	/// </summary>
	[ServiceBehavior(Namespace = "http://highspeed-solutions.net/Logging/v100", MaxItemsInObjectGraph = int.MaxValue)]
	public class LogServer : ILogServer
	{
		#region Fields
		private readonly object lockInstance;
		private readonly object lockValidate;
		private LogConfiguration logConfig;
		private bool initialized;

		#region DBLog
		private string dbConnStr;
		const string tempConfigId = "tempEventLog";
		const string defaultDb = "<default>";
		#endregion

		#endregion

		#region Constructor
		/// <summary>
		/// Default Constructor
		/// </summary>
		public LogServer()
		{
			this.lockInstance = new object();
			LogConfiguration config;
			try
			{
				config = LogConfiguration.LoadInstance();
			}
			catch
			{
				config = new LogConfiguration();
				config.SaveInstance();
			}
			this.SetConfigInternal(config);
			this.lockValidate = new object();
		}
		#endregion

		#region Methods

		/// <summary>
		/// Actually performs the write to the EventLog
		/// </summary>
		/// <param name="entry">The LogEntry to write</param>
		private int WriteInternal(LogEntry entry)
		{
			int eventId = 0;
			System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
			try { }
			finally
			{
				#region Write entry
				try
				{
					switch (this._logType)
					{
						case EventLogType.Database:
							eventId = WriteInternalToDatabase(entry);
							break;

						default:
							WriteInternalToMachine(entry);
							break;
					}
				}
				catch (Exception ex)
				{
					string errmsg = "Exception writing to the Log: " + ex.ToString() + "\r\n\r\nOriginating Exception: " + entry.Message;
					LogServer.WriteToMachineEventLog(errmsg, MachineEventLogSource.HSSLogService, EventLogEntryType.Error);
				}
				#endregion
			}
			return eventId;
		}
		private int WriteInternalToDatabase(LogEntry entry)
		{
			int eventId = 0;
			using (DataAccess da = new DataAccess(dbConnStr))
			{
				da.AddWithValue(LogDatabase.log_Message, entry.Message);
				da.AddWithValue(LogDatabase.log_EventTypeId, entry.EventType);
				da.AddWithValue(LogDatabase.log_Category, entry.Category);
				da.AddWithValue(LogDatabase.log_ApplicationName, entry.ApplicationName);
				da.AddWithValue(LogDatabase.log_ReferenceNumber, entry.ReferenceNumber);
				da.AddWithValue(LogDatabase.log_CreatedDate, entry.CreatedDate);
				if (string.IsNullOrEmpty(entry.XmlString))
				{
					da.AddWithValue(LogDatabase.log_AttachmentString, new byte[] { });
					da.AddWithValue(LogDatabase.log_AttachmentContentType, string.Empty);
				}
				else
				{
					da.AddWithValue(LogDatabase.log_AttachmentString, Encoding.UTF8.GetBytes(entry.XmlString));
					da.AddWithValue(LogDatabase.log_AttachmentContentType, MimeMapping.FromFileExtension(".xml"));
				}
				da.AddWithValue(LogDatabase.log_UserName, entry.User);

				da.ExecNonQuery(LogDatabase.logInsert, ref eventId);
			}
			entry.EventId = eventId;
			return eventId;
		}
		private void WriteInternalToMachine(LogEntry entry)
		{
			StringBuilder str = new StringBuilder();
			str.AppendLine("User: " + entry.User);
			str.AppendLine("ApplicationName: " + entry.ApplicationName);
			str.AppendLine("ReferenceNumber: " + entry.ReferenceNumber);
			str.AppendLine("Category: " + entry.Category);
			str.AppendLine("Attachment: " + (string.IsNullOrEmpty(entry.XmlString) ? "NO" : "YES"));
			str.AppendLine();
			str.Append("Message: " + entry.Message);
			if (string.IsNullOrEmpty(entry.XmlString))
				LogServer.WriteToMachineEventLog(str.ToString(), MachineEventLogSource.Workflow, entry.EventType);
			else
				LogServer.WriteToMachineEventLog(str.ToString(), MachineEventLogSource.Workflow, entry.EventType, Encoding.UTF8.GetBytes(entry.XmlString));
		}

		/// <summary>
		/// Truncate the Log, retaining the requested number of days
		/// </summary>
		/// <param name="daysToRetain">The number of days to retain</param>
		private void TruncateLogInternal(int daysToRetain)
		{
			switch (this._logType)
			{
				case EventLogType.Database:
					#region Truncate Table
					try
					{
						using (DataAccess da = new DataAccess(this.dbConnStr))
						{
							da.AddWithValue(LogDatabase.log_DaysToRetain, daysToRetain);
							da.ExecNonQuery(LogDatabase.logTruncate);
						}
					}
					catch (Exception ex)
					{
						string errmsg = "Exception truncating the Log: " + ex.ToString();
						LogServer.WriteToMachineEventLog(errmsg, MachineEventLogSource.HSSLogService, EventLogEntryType.Error);
					}
					break;
					#endregion
				default:
					break;
			}
		}

		#region Static Methods
		/// <summary>
		/// Write an entry to the Machines HSS Event Log
		/// </summary>
		/// <param name="message">The message to write</param>
		/// <param name="logSource">One of the <see cref="MachineEventLogSource"/> options</param>
		/// <param name="eventType">The event type for the entry</param>
		public static void WriteToMachineEventLog(string message, MachineEventLogSource logSource, EventLogEntryType eventType)
		{
			WriteToMachineEventLog(message, logSource, eventType, null);
		}
		/// <summary>
		/// Write an entry to the Machines HSS Event Log
		/// </summary>
		/// <param name="message">The message to write</param>
		/// <param name="logSource">One of the <see cref="MachineEventLogSource"/> options</param>
		/// <param name="eventType">The event type for the entry</param>
		/// <param name="rawData">The raw data to record with the message</param>
		public static void WriteToMachineEventLog(string message, MachineEventLogSource logSource, EventLogEntryType eventType, byte[] rawData)
		{
			if (string.IsNullOrEmpty(message))
				return;
			try
			{
				string version = typeof(LogServer).Assembly.GetName().Version.ToString(4);
				string log = "HSS " + version;
				string source = logSource.ToString() + " " + version;
				if (message.Length > 32766)
					message = message.Substring(0, 32766);
				using (EventLog ev = new EventLog(log, Environment.MachineName, source))
					ev.WriteEntry(message, eventType, 0, 0, rawData);
			}
			catch (Exception exOuter)
			{
				Console.WriteLine(exOuter.ToString());
			}
		}
		/// <summary>
		/// Connect to the database using the Sql Connection String supplied to
		/// get the default Db Name for the user specified.
		/// </summary>
		/// <param name="connectionToCheck">The Sql Connection String</param>
		/// <exception cref="ArgumentNullException">The parameter ConnectionToCheck cannot be null</exception>
		/// <returns>The default Db Name for the user defined in the Sql Connection String</returns>
		public static string GetDefaultDb(string connectionToCheck)
		{
			if (string.IsNullOrEmpty(connectionToCheck))
				throw new ArgumentNullException("connectionToCheck");

			using (SqlConnection conn = new SqlConnection(connectionToCheck))
				return GetDefaultDb(conn);
		}
		/// <summary>
		/// Using the Sql Connection supplied to get the default Db Name for the user specified.
		/// </summary>
		/// <param name="connectionToCheck">The Sql Connection to evaluate</param>
		/// <exception cref="ArgumentNullException">The parameter ConnectionToCheck cannot be null</exception>
		/// <returns>The default Db Name for the user defined in the Sql Connection String</returns>
		public static string GetDefaultDb(SqlConnection connectionToCheck)
		{
			if (null == connectionToCheck)
				throw new ArgumentNullException("connectionToCheck");

			SqlCommand cmd = null;
			SqlDataReader drr = null;
			string sql = string.Empty;
			string dbName = string.Empty;

			try
			{
				SqlConnectionStringBuilder scb = new SqlConnectionStringBuilder(connectionToCheck.ConnectionString);
				if (scb.IntegratedSecurity)
				{
					// Try domain first, assuming user is in the same Active Directory Domain as 
					// the SQL Server
					sql = string.Format(System.Globalization.CultureInfo.InvariantCulture, HSS.Logging.Resources.GetDefaultDbSQL, Environment.UserDomainName + "\\" + Environment.UserName);
					cmd = new SqlCommand(sql, connectionToCheck);
					drr = cmd.ExecuteReader();
					if (!drr.Read())
					{
						// Maybe not a domain user, but a local user on the SQL Server machine
						sql = string.Format(HSS.Logging.Resources.GetDefaultDbSQL, connectionToCheck.DataSource + "\\" + Environment.UserName);
						cmd = new SqlCommand(sql, connectionToCheck);
						drr = cmd.ExecuteReader();
						if (drr.Read())
							dbName = drr["dbname"].ToString();
					}
					else
					{
						dbName = drr["dbname"].ToString();
					}
				}
				else
				{
					sql = string.Format(HSS.Logging.Resources.GetDefaultDbSQL, scb.UserID);
					cmd = new SqlCommand(sql, connectionToCheck);
					drr = cmd.ExecuteReader();
					if (drr.Read())
						dbName = drr["dbname"].ToString();
				}

			}
			finally
			{
				if (null != cmd)
					cmd.Dispose();

				if (null != drr)
					drr.Dispose();
			}

			return dbName;
		}
		/// <summary>
		/// Connect to the database using the Sql Connection String supplied to determine if the
		/// HSS Core SQL Services are installed
		/// </summary>
		/// <param name="ConnectionToCheck">The Sql Connection String</param>
		/// <exception cref="ArgumentNullException">The parameter ConnectionToCheck cannot be null</exception>
		/// <returns>true if Installed or false if not installed or if any errors are encountered</returns>
		public static bool IsInstalled(string ConnectionToCheck)
		{
			if (string.IsNullOrEmpty(ConnectionToCheck))
				throw new ArgumentNullException("ConnectionToCheck");

			using (SqlConnection conn = new SqlConnection(ConnectionToCheck))
				return IsInstalled(conn);

		}
		/// <summary>
		/// Using the Sql Connection supplied, determine if the
		/// HSS Core SQL Services are installed
		/// </summary>
		/// <param name="ConnectionToCheck">The Sql Connection to evaluate</param>
		/// <exception cref="ArgumentNullException">The parameter ConnectionToCheck cannot be null</exception>
		/// <returns>true if Installed or false if not installed or if any errors are encountered</returns>
		public static bool IsInstalled(SqlConnection ConnectionToCheck)
		{
			if (null == ConnectionToCheck)
				throw new ArgumentNullException("ConnectionToCheck");

			try
			{
				if (ConnectionToCheck.State != System.Data.ConnectionState.Open)
					ConnectionToCheck.Open();

				using (SqlCommand cmd = new SqlCommand(HSS.Logging.Resources.IsHSSCoreInstalledSQL, ConnectionToCheck))
				{
					cmd.CommandType = System.Data.CommandType.Text;
					string installed = cmd.ExecuteScalar().ToString();
					if (string.IsNullOrEmpty(installed))
						return false;
					else
						return true;
				}
			}
			catch { }
			finally
			{
				if (null != ConnectionToCheck)
				{
					try
					{
						if (ConnectionToCheck.State == System.Data.ConnectionState.Open)
							ConnectionToCheck.Close();
					}
					catch { }
				}
			}

			return false;
		}
		#endregion

		#endregion

		#region ILogServer Members

		/// <summary>
		/// The LogType of the LogginService
		/// </summary>
		public EventLogType LogType
		{
			get { return _logType; }
		} EventLogType _logType;

		/// <summary>
		/// Gets the current EventLogType.
		/// </summary>
		/// <returns>The <see cref="EventLogType"/>.</returns>
		public EventLogType GetLogType()
		{
			return this.LogType;
		}

		/// <summary>
		/// A method a client object can call to validate object existance
		/// </summary>
		/// <returns>true</returns>
		public bool Ping()
		{
			return true;
		}

		/// <summary>
		/// Set the Log Configuration for the instance
		/// </summary>
		/// <param name="id">The unique Id for this Configuration</param>
		/// <param name="name">The friendly name for this Configuration</param>
		/// <param name="logType">The Type of log to write event entries to</param>
		/// <param name="autoTruncate">Indicate whether or not to auto truncate the eventlog</param>\>
		/// <param name="truncateAt">If AutoTruncate is true indicates the time of day in which to execute the Truncate Command</param>
		/// <param name="daysToRetain">If AutoTruncate is true indicates the number of days to retain</param>
		/// <param name="dbConnString">The Id of the Database Configuration to use</param>
		public void SetConfig(string id, string name, int logType, bool autoTruncate, DateTime truncateAt, int daysToRetain, string dbConnString)
		{
			lock (lockInstance)
			{
				// Save Configuration
				_logType = (EventLogType)logType;
				LogConfiguration config = new LogConfiguration(id, name, _logType, autoTruncate, truncateAt, daysToRetain, dbConnString);
				config.SaveInstance();

				// Reset Configuration
				SetConfigInternal(config);

			}
		}
		private void SetConfigInternal(LogConfiguration logConfig)
		{
			// Set Configuration
			this.logConfig = logConfig;
			this._logType = logConfig.LogType;

			#region Custom Initialization
			switch (this._logType)
			{
				case EventLogType.Database:
					#region Database Log
					this.dbConnStr = logConfig.DbConnString;
					if (null == this.dbConnStr)
						throw new ArgumentNullException("The Database ConnectionString cannot be null when the Log Type is of set to Database.", "EventLogConfiguration.DbConnString");
					break;
					#endregion
				default:
					#region Machine Log
					this.dbConnStr = null;
					break;
					#endregion
			}
			#endregion

			#region AutoTruncate Service
			bool autoTruncateActive = logConfig.AutoTruncate;
			if (autoTruncateActive && !AutoTruncateService.IsStarted)
				AutoTruncateService.Start(logConfig.TruncateAt);
			else if (!autoTruncateActive && AutoTruncateService.IsStarted)
				AutoTruncateService.Stop();
			#endregion

			this.initialized = true;
		}

		/// <summary>
		/// Returns an EventLog Configuration
		/// </summary>
		/// <returns>An EventLog Configuration</returns>
		public LogConfiguration GetConfig()
		{
			return this.logConfig;
		}

		/// <summary>
		/// Validate the database connection for event logging
		/// </summary>
		/// <param name="verbose">Indicate if the results are to be displayed</param>
		/// <returns>The <see cref="HSS.Logging.ValidationResults"/> instance containing the results</returns>
		public ValidationResults ValidateDbConnection(bool verbose)
		{
			lock (this.lockValidate)
			{

				ValidationResults results = new ValidationResults();
				results.Success = true;
				results.ShowVerbose = verbose;

				string strErr = string.Empty;

				try
				{
					using (DataAccess da = new DataAccess(this.logConfig.DbConnString))
					{
						if (da.Connection.InitialCatalog == defaultDb)
							da.Connection.InitialCatalog = string.Empty;

						if (!da.IsConnectionValid(out strErr))
						{
							#region Failure
							results.Success = false;
							results.Message = strErr;
							#endregion
						}
						else
						{
							#region Success

							if (string.IsNullOrEmpty(da.Connection.InitialCatalog))
							{
								string defaultDbName = GetDefaultDb(da.ConnectionString);
								if (!string.IsNullOrEmpty(defaultDbName))
								{
									da.Connection.InitialCatalog = defaultDbName;
									lock (lockInstance)
									{
										this.logConfig.DbConnString = da.ConnectionString;
										this.logConfig.SaveInstance();
										this.SetConfigInternal(this.logConfig);
									}
								}
							}

							if (!string.IsNullOrEmpty(da.Connection.InitialCatalog))
								results.CoreDBInstalled = IsInstalled(this.logConfig.DbConnString);

							#endregion
						}
					}
				}
				catch (Exception ex)
				{
					results.Success = false;
					results.Error = ex;
				}

				return results;

			}
		}

		/// <summary>
		/// Save an attachment to the HSS Database
		/// </summary>
		/// <param name="entryId">The Id of the pre-existing EventLog entry to attach.</param>
		/// <param name="content">The Content of the Attachment.</param>
		/// <param name="fileName">The File Name associated with this attachment. Uses the extension of the file to determine the Content-Type.</param>
		/// <returns>The AttachmentID</returns>
		/// <exception cref="InvalidOperationException">You can only add attachments when the LogType is to Database.</exception>
		public int AttachFile(int entryId, byte[] content, string fileName)
		{
			if (this._logType == EventLogType.Machine)
				throw new InvalidOperationException("You can only add attachments when the LogType is Database.");

			string name = Path.GetFileNameWithoutExtension(fileName);
			string ext = Path.GetExtension(fileName);
			string ctt = MimeMapping.FromFileName(fileName);

			return AttachContent(entryId, content, ctt, name, ext);
		}

		/// <summary>
		/// Save an attachment to the HSS Database
		/// </summary>
		/// <param name="EntryId">The Id of the pre-existing EventLog entry to attach.</param>
		/// <param name="content">The Content of the Attachment.</param>
		/// <param name="contentType">The Mime Content-Type of the Attachment.</param>
		/// <param name="fileNameWithOutExtention">The File Name associated with this attachment with out the extension (.ext).</param>
		/// <param name="extensionWithDot">The File Extension associated with this attachment (.ext).</param>
		/// <returns>The AttachmentID</returns>
		/// <exception cref="InvalidOperationException">You can only add attachments when the LogType is to Database.</exception>
		public int AttachContent(int EntryId, byte[] content, string contentType, string fileNameWithOutExtention, string extensionWithDot)
		{
			if (this._logType == EventLogType.Machine)
				throw new InvalidOperationException("You can only add attachments when the LogType is to Database.");

			int attachmentId = 0;

			try
			{
				using (DataAccess da = new DataAccess(dbConnStr))
				{
					// Insert Attachment
					da.AddParam(LogDatabase.attachment_Content, content, SqlDbType.VarBinary);
					da.AddParam(LogDatabase.attachment_ContentType, contentType, SqlDbType.VarChar, 100);
					da.AddParam(LogDatabase.attachment_Extension, extensionWithDot, SqlDbType.VarChar, 10);
					da.AddParam(LogDatabase.attachment_File, fileNameWithOutExtention, SqlDbType.VarChar, 256);

					da.ExecNonQuery(LogDatabase.attachmentInsert, ref attachmentId);

					if (attachmentId > 0)
					{
						// Update EventLog entry
						da.AddWithValue(LogDatabase.log_EventId, EntryId);
						da.AddWithValue(LogDatabase.log_AttachmentId, attachmentId);
						da.ExecNonQuery(LogDatabase.attachmentSet);
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				throw;
			}

			// Return Attachment Id
			return attachmentId;
		}

		/// <summary>
		/// Retrieve an Attachment from the Database
		/// </summary>
		/// <param name="attachmentId">The id of the attachment to retrieve</param>
		/// <returns>A <see cref="HSS.Logging.LogEntryAttachment"/></returns>
		public LogEntryAttachment GetAttachment(int attachmentId)
		{
			LogEntryAttachment att = new LogEntryAttachment();
			att.AttachmentID = attachmentId;
			if (attachmentId == 0)
				return att;

			try
			{
				using (DataAccess da = new DataAccess(this.logConfig.DbConnString))
				{
					da.AddWithValue(LogDatabase.attachment_Id, attachmentId);
					DataRowReader drr = da.ExecDataRowReader(LogDatabase.attachmentGet);
					if (drr.Read())
					{
						att.Content = (byte[])drr[LogDatabase.attachment_Content];
						att.ContentType = drr[LogDatabase.attachment_ContentType].ToString();
						att.Extension = drr[LogDatabase.attachment_Extension].ToString();
						att.LocalFileName = drr[LogDatabase.attachment_File].ToString();
						if (string.IsNullOrEmpty(att.LocalFileName))
							att.LocalFileName = "temp-" + Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
						att.DisplayName = att.LocalFileName + att.Extension;
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				throw;
			}
			return att;
		}

		/// <summary>
		/// Gets a filtered list of entries from the HSS Database EventLog table.
		/// </summary>
		/// <param name="pages">Reference to the number of pages.</param>
		/// <param name="page">The desired page.</param>
		/// <param name="recPerPage">The number of records per page.</param>
		/// <param name="eventTypeMask">The Mask of EventTypes to filter for.</param>
		/// <param name="applicationName">The Application to filter for.</param>
		/// <param name="referenceNumber">The Reference Number to filter for.</param>
		/// <param name="category">The category to filter for.</param>
		/// <param name="userName">The UserName associated with the entry.</param>
		/// <param name="beginDate">The Created Date of the entry must be greater than or equal to this date.</param>
		/// <param name="endDate">The Created Date of the entry must be less than or equal to this date.</param>
		/// <returns>A list of LogRecords containing the EventLog data.</returns>
		public List<LogRecord> GetEntries(ref int pages, int page, int recPerPage, int eventTypeMask, string applicationName, string referenceNumber, string category, string userName, DateTime beginDate, DateTime endDate)
		{
			//@Page				INT				= 1,
			//@RecsPerPage		INT				= 30,
			//@EventTypeId		INT				= 0,
			//@ApplicationName	NVARCHAR(256)	= NULL,
			//@ReferenceNumber	NVARCHAR(256)	= NULL,
			//@Category			NVARCHAR(256)	= NULL,
			//@UserName			NVARCHAR(256)	= NULL,
			//@BeginDate		DATETIME		= NULL,
			//@EndDate			DATETIME		= NULL	
			var list = new List<LogRecord>();
			try
			{
				using (var da = new DataAccess(this.logConfig.DbConnString))
				{
					da.AddParams(LogDatabase.filterEvents, new object[] { page, recPerPage, eventTypeMask, applicationName, referenceNumber, category, userName, beginDate, endDate });
					SqlCommand cmd;
					using (var dr = da.ExecSqlDataReader(LogDatabase.filterEvents, out cmd))
						while (dr.Read())
							list.Add(new LogRecord(dr));
					pages = DataAccess.GetReturnValue(cmd);

				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				throw;
			}
			return list;
		}

		/// <summary>
		/// Retrieve the list of Categories from the Database.
		/// </summary>
		/// <returns>A List of <see cref="LogCategory"/> objects.</returns>
		public List<LogCategory> GetCategories()
		{
			List<LogCategory> values = new List<LogCategory>();
			try
			{
				using (DataAccess da = new DataAccess(this.logConfig.DbConnString))
				{
					using (var dr = da.ExecSqlDataReader(LogDatabase.categorySelect))
					{
						while (dr.Read())
							values.Add(new LogCategory(dr));
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				throw;
			}
			return values;
		}

		/// <summary>
		/// Retrieve the list of Event Types from the Database.
		/// </summary>
		/// <returns>A List of <see cref="LogEventType"/> objects.</returns>
		public List<LogEventType> GetEventTypes()
		{
			List<LogEventType> values = new List<LogEventType>();
			try
			{
				using (DataAccess da = new DataAccess(this.logConfig.DbConnString))
				{
					using (SqlDataReader dr = da.ExecSqlDataReader(LogDatabase.eventTypeSelect))
					{
						while (dr.Read())
							values.Add(new LogEventType(dr));
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteException(ex);
				throw;
			}
			return values;
		}

		/// <summary>
		/// Truncate the EventLog using the Retention Policy for the Log
		/// </summary>
		public void TruncateLog()
		{
			if (!initialized)
				throw new InvalidOperationException("The LogServer must first be initialized before truncating can occur");

			lock (lockInstance)
				this.TruncateLogInternal(this.logConfig.DaysToRetain);
		}

		/// <summary>
		/// Truncate the Log, retaining the requested number of days
		/// </summary>
		/// <param name="DaysToRetain">The number of days to retain</param>
		public void TruncateLog(int DaysToRetain)
		{
			if (!initialized)
				throw new InvalidOperationException("The LogServer must first be initialized before truncating can occur");

			lock (lockInstance)
				this.TruncateLogInternal(DaysToRetain);
		}

		/// <summary>
		/// Write an entry to a Log
		/// </summary>
		/// <param name="message">The message to write.</param>
		/// <param name="userName">The name of the person or program writing this message.</param>
		/// <param name="category">The category of the program that is writing this message.</param>
		/// <param name="xmlString">The Xml String to attach to this entry.</param>
		/// <param name="applicationName">The name of the application this entry is associated with.</param>
		/// <param name="referenceNumber">A reference number to associate with the entry.</param>
		/// <param name="eventType">The event type for the entry.</param>
		/// <remarks>eventType: 1 = Success; 2 = Error; 3 = Information, 4 = Success Audit, 5 = Failure Audit</remarks>
		/// <exception cref="InvalidOperationException">Cannot write to the Log when it's closed.</exception>
		public int WriteEvent(string message, string userName, string category, string xmlString, string applicationName, string referenceNumber, System.Diagnostics.EventLogEntryType eventType)
		{
			if (!initialized)
				throw new InvalidOperationException("EventLog must first be initialized before reading or writing");

			lock (lockInstance)
			{
				if (!initialized)
					throw new InvalidOperationException("The LogServer must first be initialized before reading or writing");

				LogEntry le = new LogEntry(message, userName, category, xmlString, applicationName, referenceNumber, DateTime.Now, eventType);
				int entryId = this.WriteInternal(le);
				return entryId;
			}
		}

		/// <summary>
		/// Write an entry to a Log
		/// </summary>
		/// <param name="entry">The Log entry to write</param>
		/// <exception cref="InvalidOperationException">Cannot write to the Log when it's closed.</exception>
		/// <returns>The id of the new entry</returns>
		public int WriteEntry(LogEntry entry)
		{
			if (!initialized)
				throw new InvalidOperationException("EventLog must first be initialized before reading or writing");

			lock (lockInstance)
			{
				if (!initialized)
					throw new InvalidOperationException("The LogServer must first be initialized before reading or writing");

				int entryId = this.WriteInternal(entry);
				return entryId;
			}
		}

		#endregion
	}
	#endregion
}